package gate

import (
	"errors"
	"fmt"
	"github.com/256dpi/gomqtt/packet"
	"github.com/liu-junyong/go-logger/logger"
	"encoding/json"
	"time"
	. "github.com/liu-junyong/gohelper"
	"github.com/256dpi/gomqtt/broker"
)




type  PlayerManager struct{
	Tm	* TcpManager
	Back *MyBackend
}

func (this* PlayerManager)Init(tm*TcpManager){
	this.Tm	= tm
}



type FullPackage struct {
	Uid        int32	`json:"uid"`
	Code       int32	`json:"code"`
	UpdateUser UserInfoAdapt `json:"2010"`
	Data       map[string]interface{}	`json:"data"`
	Dt         string
}




type UserInfoAdapt struct {
	UnionID              string `json:"clientid"`
	Location_update_time int32
	IP                   string
	Sex                  int32
	Version              string
	Uid                  int32
	NickName             string
	HeadIMGURl           string
	numof_cards_1        int32
	numof_cards_2        int32
	numof_cards_3        int32
	gate_cliend_id       string
	Location_CN          string
	Location             string `json:"location"`
}




func (this* PlayerManager)OnClient(client *broker.Client,bt []byte){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	pos := 0
	for i:=0; i < 100 && i < len(bt) ;i++ {
		if bt[i] == '{' {
			pos = i
			break
		}
	}
	js := bt[pos:]
	//mqttclientid := bt[:pos]
	//clientid := string(mqttclientid)
	//if clientid == "" {
	//	clientid = client.ID()
	//}
	//
	//logger.Info( string(mqttclientid) )

	logger.Info( string(js) )
	var adp FullPackage
	json.Unmarshal(js, &adp)
	if adp.Code > 0 {
		this.OnUser(client.ID(),&adp)
	}


}




func (this* PlayerManager)OnUser(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	switch adp.Code {
	case 2001:
		this.Login(clientid,adp)
	case 2002:
		this.Logout(clientid,adp)
	case 2003:
		this.Sync(clientid,adp)
	case 2008:
		this.Shiming(clientid,adp)
	case 2101:
		this.dealClub(clientid, adp)
	case 2102:
		this.fetchClubRoomList(clientid, adp)
	case 3001:
		this.createRoom(clientid, adp)
	case 2020:
		this.robotCreateRoom(clientid, adp)
	case 3002:
		this.joinRoom(clientid, adp)
	case 3003:
		this.exitRoom(clientid, adp)
	case 3004:
		this.playerReady(clientid, adp)
	case 3005:
		this.startGame(clientid, adp)
	case 3007:
		this.submitInfo(clientid, adp)
	case 3008:
		this.chat(clientid, adp)
	case 3009:
		this.jiesan(clientid, adp)
	case 3010:
		this.kickoff(clientid, adp)
	case 3013:
		this.syncPlayerInfo(clientid, adp)
	case 3014:
		this.fetchDaikaiList(clientid, adp)
	case 3015:
		this.fetchDaikaiFinishedList(clientid, adp)
	case 3016:
		this.jiesanDaikaiRoom(clientid, adp)
	case 3017:
		this.playerReadyCancel(clientid, adp)
	case 3019:
		this.adminJiesan(clientid, adp)
	case 3100:
		this.fetchZhanji(clientid, adp)
	case 3323:
		this.removeRoomFromBack(clientid, adp)
	case 3301:
		this.playerEnterOrLeaveRoomFromBack(clientid, adp)
	case 3102:
		this.submitFeedBack(clientid, adp)
	case 3020:
		this.robotCreateRoomFromBack(clientid, adp)
	case 3021:
		this.route2MatchServer(clientid, adp)
	case 3022:
		this.route2MatchServer(clientid, adp)
	case 2023:
		this.game2MatchServer(clientid, adp)
	case 2024:
		this.broadcastMatchServer(clientid, adp)
	case 2025:
		this.game2ClubServer(clientid, adp)
	case 3997:
		this.getRoomOptions(clientid, adp)
	case 3998:
		this.kickoffFromNode(clientid, adp)
	}
	if adp.Code >= 4000  {
		this.routeToRoom(clientid, adp);

	}

}




func (this* PlayerManager)Logout(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}



func (this* PlayerManager)Login(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

	ctime := time.Now()
	lTime := ctime.Format("2006-01-02 15:04:05")

	adp.Data["last_login_time"] = ctime.Unix()
	adp.Data["ltime"] = lTime

	delete(adp.Data, "sign")
	delete(adp.Data, "time")
	delete(adp.Data, "_id")
	delete(adp.Data, "uid")
	delete(adp.Data, "needComp")
	delete(adp.Data, "isnative")

	userinfo := SaveUserInfo( &adp.Data, clientid, false, false)
	preroom := GetExistRoom(adp.Uid)

	this.SendPlayer2001(clientid,adp,userinfo,preroom)

	if preroom == nil {
		//发送给服务器 短线重来请求
		err :=sendPlayerReconnect(userinfo,preroom,clientid)
		if err!=nil{
			//todo 都发送失败了 就别让客户端等待了!
			logger.Error(err.Error())
		}
	}
}

func sendPlayerReconnect(userinfo *map[string]interface{},preroom *map[string]interface{},clientid string)error  {
	if preroom==nil||userinfo==nil{
		logger.Error("preroom  为空")
		return errors.New("preroom  为空")
	}
	if (*preroom)["uri"]==nil{
		logger.Error("preroom  uri为空")
		return errors.New("preroom  uri为空")
	}
	uri,ok:=(*preroom)["uri"].(string)

	if !ok{
		logger.Error("preroom 不是正确的格式uri:",(*preroom)["uri"])
		return errors.New(fmt.Sprintf("preroom 不是正确的格式uri:%v",(*preroom)["uri"]))
	}

	msg:=map[string]interface{}{
		"code":3221,
		"uid":clientid,
	}
	data:=map[string]interface{}{
		"room_id":(*preroom)["room_id"],
		"option":(*preroom)["option"],
		"roomtoken":(*preroom)["roomtoken"],
		"robot":(*preroom)["robot"],
		"group":(*preroom)["group"],
	}
	msg["data"] = data
	msg["2010"] = appendPlayerInfo(userinfo)

	buf,err:= json.Marshal(msg)
	if err!=nil{
		logger.Error("短线重连编码失败 err:",err.Error())
		return err
	}

	//发送到服务器
	err = g_tcpManager.Send2backbyuri(uri,clientid,string(buf))
	if err!=nil{
		logger.Error(err.Error())
	}
	return err
}

func appendPlayerInfo(userinfo *map[string]interface{}) map[string]interface{} {
	info:=map[string]interface{}{}
	for k,v:=range *userinfo{
		info[k]=v
	}
	info["nickname"] = EncodeUriComponent(info["nickname"].(string))
	return info
}

type dbuserinfo struct{
	_id		int32
	unionid string
}


func (this* PlayerManager)Sync(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)
}

func (this* PlayerManager)Shiming(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}

func (this* PlayerManager)dealClub(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}





func (this* PlayerManager)fetchClubRoomList(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}





func (this* PlayerManager)createRoom(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	//并发指令处理，同一个玩家，相同或者类似指令同一时刻只能一个线程执行。

	//各种判断能不能开房

	//已经有开好的房间了，让玩家断线重连试试

	//是否考虑比赛场金币场互斥

	//是否代开，代开的人是否有权限，是否有足够的房卡

	//客户端当前版本是否兼容


	//选择一个game开房
	mapId := Json2int(adp.Data["map_id"])
	data,_ := json.Marshal(adp)
	//TcpManager.GetSessionUp(mapId)

	session := g_tcpManager.GetSessionUp(mapId)
	if session != nil {
		session.Send2BackJson(clientid, string(data));
	} else {
		logger.Error("通过当前mapid没有找到后端服务",mapId)
		msg := FullPackage{}
		msg.Code = -1
		msg.Dt="{'errorMsg':'游戏服务器连接失败','errorCode':-1}"

		msg.Data["errorMsg"]="游戏服务器连接失败"
		msg.Data["errorCode"]=-1

		this.SendPlayer(clientid,&msg)
	}



	logger.Info(clientid, adp)
}





func (this* PlayerManager)robotCreateRoom(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}





func (this* PlayerManager)joinRoom(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}





func (this* PlayerManager)exitRoom(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)
	uri := Json2String( adp.Data["uri"] )
	adp.Code = 3001
	data,_ := json.Marshal(adp)
	g_tcpManager.Send2backbyuri(uri,clientid, string(data))
}





func (this* PlayerManager)playerReady(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}





func (this* PlayerManager)fetchZhanji(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}





func (this* PlayerManager)adminJiesan(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}




func (this* PlayerManager)playerReadyCancel(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}





func (this* PlayerManager)jiesanDaikaiRoom(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}





func (this* PlayerManager)fetchDaikaiFinishedList(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}




func (this* PlayerManager)fetchDaikaiList(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}





func (this* PlayerManager)syncPlayerInfo(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}





func (this* PlayerManager)kickoff(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}






func (this* PlayerManager)jiesan(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}






func (this* PlayerManager)chat(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}





func (this* PlayerManager)getRoomOptions(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}






func (this* PlayerManager)kickoffFromNode(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}






func (this* PlayerManager)submitInfo(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}







func (this* PlayerManager)game2ClubServer(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}








func (this* PlayerManager)broadcastMatchServer(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}








func (this* PlayerManager)game2MatchServer(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}







func (this* PlayerManager)route2MatchServer(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}







func (this* PlayerManager)robotCreateRoomFromBack(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}







func (this* PlayerManager)submitFeedBack(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}








func (this* PlayerManager)playerEnterOrLeaveRoomFromBack(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}







func (this* PlayerManager)removeRoomFromBack(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}








func (this* PlayerManager)startGame(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}




func (this* PlayerManager)routeToRoom(clientid string,adp *FullPackage){
	defer func() {
		if r := recover(); r != nil {
			logger.Error(r)
		}
	}()

	logger.Info(clientid,adp)

}


func (this *PlayerManager)SendPlayer2001(clientid string,adp *FullPackage,userinfo *map[string]interface{},preroom *map[string]interface{} ){
	//"{'code':2001,'data':{'uid':%d,'is_new':%b,'is_reconnect':%d,'fangka_num':1,'refer':%d,'parent_id':%d,
	// 'numof_cards':[%d,%d,%d],'ip':'%s','weixin':'%s','triggers':[%s],'map_conf':%s,'opt_conf':%s,'loc':'%s','locCN':'%s','locUpdTime':%d,
	// 'now':%d,'ts':%s,'hasSignin':%b, 'hasShiMing':%b,'hasHeadImgFrame':%b,'xiaoweixin':'%s'}}",
	//	uid, isNew, preRoom == null ? 0 : 1, refer, parent_id,
	//	numof_cards_1, numof_cards_2, numof_cards_3,
	//	player.getIp(), HttpRequestUtils.getWeixin(), Constants.triggersString, Constants.mapConfString, Constants.optConfString,
	//	player.getLocation(), player.getLocationCN(), player.getLocationUpdateTime(), (int) (System.currentTimeMillis() / 1000),
	//	ts, hasSignin, !(player.getRealName() == null || player.getIdentityCardId() == null || player.getRealName().equals("") || player.getIdentityCardId().equals("")),
	// player.isHasHeadImgFrame(), Constants.xiaoWeiXin

	msg := FullPackage{}
	msg.Code = 2001

	data := make(map[string]interface{})
	data["uid"]= adp.Uid
	if preroom != nil {
		data["is_reconnect"]= 1
	}
	data["refer"] = (*userinfo)["refer"]
	data["parent_id"] = (*userinfo)["parent_id"]

	numof_cards := make( []int32,0)
	numof_cards = append(numof_cards,  Json2int((*userinfo)["numof_cards_1"]) ,  Json2int((*userinfo)["numof_cards_2"]) , Json2int((*userinfo)["numof_cards_3"])   )
	data["numof_cards"] = numof_cards
	data["now"] =  time.Now().Unix()


	bt,_ := json.Marshal(msg)

	client:=g_playerManager.Back.activeClients[clientid]
	msgs:=&packet.Message{
		Payload:bt,
	}
	this.Back.Publish(client,msgs,nil)

	//client := this.Back.GetClient(clientid)
	//if client != nil {
	//	client.Publish()
	//}
	//g_tcpManager.Send2backbyuri()
}


func (this *PlayerManager)SendPlayer(clientid string,msg *FullPackage){
	bt,_ := json.Marshal(msg)
	client:=g_playerManager.Back.activeClients[clientid]
	msgs:=&packet.Message{
		Payload:bt,
	}
	this.Back.Publish(client,msgs,nil)
}